#include "unifiedcachemanager.h"
#include "fileidentitymanager.h"
#include "unifiedfileinfo.h"
#include "pathmanager.h"
#include <QMutex>
#include <QMutexLocker>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <QFile>
#include <QDir>
#include <QFileInfo>
#include <QDebug>
#include <QThread>
#include <QDirIterator>
#include <QApplication>
#include <QTextStream>
#include <QRegularExpression>
#include <QCryptographicHash>
#include <QStandardPaths>
// 静态成员初始化
UnifiedCacheManager* UnifiedCacheManager::s_instance = nullptr;
QMutex UnifiedCacheManager::s_mutex;
UnifiedCacheManager::UnifiedCacheManager(QObject *parent)
    : QObject(parent)
    , m_cacheDirectoryInitialized(false)
    , m_maxCacheSize(10LL * 1024 * 1024 * 1024)  // 10GB默认
    , m_maxCacheAge(30)  // 30天默认
    , m_cachedActualSize(0)
    , m_spaceMonitorTimer(nullptr)
    , m_spaceThresholdGB(2)
    , m_spaceMonitoringActive(false)
    , m_lastSpaceCheckResult(true)
{
    // 使用PathManager获取跨平台标准缓存目录
    QString cachePath = PathManager::getCacheDirectory();
    setCacheDirectory(cachePath);
    // 初始化导出缓存
    loadExportCache();
    // 不再清理旧缓存，因为程序启动时已经清除了
}
UnifiedCacheManager* UnifiedCacheManager::instance()
{
    // 双重检查锁定模式确保线程安全的单例
    if (s_instance == nullptr) {
        QMutexLocker locker(&s_mutex);
        if (s_instance == nullptr) {
            s_instance = new UnifiedCacheManager();
        }
    }
    return s_instance;
}
QString UnifiedCacheManager::getCacheDirectory() const
{
    if (!m_cacheDirectoryInitialized) {
        m_cacheDirectory = determineCacheDirectory();
        m_cacheDirectoryInitialized = true;
    }
    return m_cacheDirectory;
}
void UnifiedCacheManager::setCacheDirectory(const QString& dir)
{
    QMutexLocker locker(&m_mutex);
    m_cacheDirectory = dir;
    QDir().mkpath(m_cacheDirectory);
}
bool UnifiedCacheManager::cacheDirectoryExists() const
{
    return QDir(getCacheDirectory()).exists();
}
QString UnifiedCacheManager::determineCacheDirectory() const
{
    // 使用PathManager获取跨平台标准缓存目录，而不是程序目录
    return PathManager::getCacheDirectory();
}
QList<UnifiedCacheManager::CacheEntry> UnifiedCacheManager::scanCacheEntries() const
{
    QList<CacheEntry> entries;
    QString cacheDir = getCacheDirectory();
    QDir dir(cacheDir);
    if (!dir.exists()) {
        return entries;
    }
    QStringList subdirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
    for (const QString& subdir : subdirs) {
        QString subdirPath = cacheDir + "/" + subdir;
        // 只支持MD5哈希格式的目录名（32位十六进制字符串）
        bool isValidCacheDir = (subdir.length() == 32 && QRegularExpression("^[a-f0-9]+$").match(subdir).hasMatch());
        if (isValidCacheDir) {
            CacheEntry entry = scanSingleCacheEntry(subdirPath);
            if (entry.isValid) {
                entries.append(entry);
            } else {
            }
        } else {
        }
    }
    return entries;
}
UnifiedCacheManager::CacheEntry UnifiedCacheManager::scanSingleCacheEntry(const QString& entryPath) const
{
    CacheEntry entry;
    QDir dir(entryPath);
    if (!dir.exists()) {
        return entry; // isValid = false
    }
    // 设置基本信息
    entry.hash = dir.dirName();
    entry.fullPath = entryPath;
    entry.isValid = false;
    // 计算目录大小和页面数量
    entry.sizeBytes = calculateDirectorySize(entryPath);
    entry.pageCount = countPageFiles(entryPath);
    if (entry.pageCount > 0) {
        entry.isValid = true;
        // 获取最后修改时间
        QFileInfo dirInfo(entryPath);
        entry.lastModified = dirInfo.lastModified();
        // 尝试从manifest.json读取源文件路径
        entry.sourcePath = readSourcePathFromManifest(entryPath);
    }
    return entry;
}
qint64 UnifiedCacheManager::calculateDirectorySize(const QString& dirPath) const
{
    qint64 totalSize = 0;
    QDir dir(dirPath);
    QStringList files = dir.entryList(QDir::Files);
    for (const QString& file : files) {
        QString filePath = dirPath + "/" + file;
        QFileInfo fileInfo(filePath);
        totalSize += fileInfo.size();
    }
    return totalSize;
}
int UnifiedCacheManager::countPageFiles(const QString& dirPath) const
{
    QDir dir(dirPath);
    QStringList files = dir.entryList(QDir::Files);
    int pageCount = 0;
    for (const QString& file : files) {
        if (file.startsWith("page_") && file.endsWith(".png")) {
            pageCount++;
        }
    }
    return pageCount;
}
QString UnifiedCacheManager::readSourcePathFromManifest(const QString& dirPath) const
{
    QString manifestPath = dirPath + "/manifest.json";
    QFile file(manifestPath);
    if (!file.exists()) {
        return QString();
    }
    if (!file.open(QIODevice::ReadOnly)) {
        return QString();
    }
    QByteArray data = file.readAll();
    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull()) {
        return QString();
    }
    QJsonObject obj = doc.object();
    return obj.value("file").toString();
}
qint64 UnifiedCacheManager::getTotalCacheSize() const
{
    QList<CacheEntry> entries = scanCacheEntries();
    qint64 totalSize = 0;
    for (const auto& entry : entries) {
        totalSize += entry.sizeBytes;
    }
    return totalSize;
}
int UnifiedCacheManager::getCacheEntryCount() const
{
    return scanCacheEntries().size();
}
bool UnifiedCacheManager::deleteCacheEntry(const QString& hash)
{
    QString cacheDir = getCacheDirectory();
    QString entryPath = cacheDir + "/" + hash;
    QDir dir(entryPath);
    if (!dir.exists()) {
        return false;
    }
    bool success = dir.removeRecursively();
    if (success) {
        emit cacheEntryDeleted(hash);
        emit cacheSizeChanged(getTotalCacheSize());
    }
    return success;
}
bool UnifiedCacheManager::deleteAllCache()
{
    QString cacheDir = getCacheDirectory();
    QDir dir(cacheDir);
    if (!dir.exists()) {
        return false;
    }
    bool success = dir.removeRecursively();
    if (success) {
        emit allCacheDeleted();
        emit cacheSizeChanged(0);
    }
    return success;
}
bool UnifiedCacheManager::deleteCacheEntries(const QStringList& hashes)
{
    bool allSuccess = true;
    for (const QString& hash : hashes) {
        if (!deleteCacheEntry(hash)) {
            allSuccess = false;
        }
    }
    return allSuccess;
}
bool UnifiedCacheManager::isCacheEntryValid(const QString& hash) const
{
    QString cacheDir = getCacheDirectory();
    QString entryPath = cacheDir + "/" + hash;
    QDir dir(entryPath);
    if (!dir.exists()) {
        return false;
    }
    return countPageFiles(entryPath) > 0;
}
UnifiedCacheManager::CacheEntry UnifiedCacheManager::getCacheEntryInfo(const QString& hash) const
{
    QString cacheDir = getCacheDirectory();
    QString entryPath = cacheDir + "/" + hash;
    return scanSingleCacheEntry(entryPath);
}
void UnifiedCacheManager::cleanupEmptyDirectories() const
{
    QString cacheDir = getCacheDirectory();
    QDir dir(cacheDir);
    if (!dir.exists()) {
        return;
    }
    QStringList subdirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
    for (const QString& subdir : subdirs) {
        QString subdirPath = cacheDir + "/" + subdir;
        QDir subdirDir(subdirPath);
        // 检查目录是否为空
        if (subdirDir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot).isEmpty()) {
            subdirDir.removeRecursively();
        }
    }
}
// ========== 从CacheManager整合的功能 ==========
void UnifiedCacheManager::setMaxCacheSize(qint64 sizeMB)
{
    QMutexLocker locker(&m_mutex);
    m_maxCacheSize = sizeMB * 1024 * 1024;
}
void UnifiedCacheManager::setMaxCacheAge(int days)
{
    QMutexLocker locker(&m_mutex);
    m_maxCacheAge = days;
}
QString UnifiedCacheManager::getCacheFilePath(const QString& cacheKey)
{
    // 从cacheKey中提取文件标识和页面信息
    // cacheKey格式: fileIdentity_type_pageindex
    QStringList parts = cacheKey.split('_');
    if (parts.size() != 3) {
        return QString();
    }
    QString fileIdentity = parts[0];
    QString type = parts[1];
    QString pageIndex = parts[2];
    // 创建子目录结构：fileIdentity/00001.png
    int pageNum = pageIndex.toInt();
    QString fileName = QString("%1.png").arg(pageNum, 5, 10, QChar('0'));
    QDir cacheDir(m_cacheDirectory);
    QDir fileDir = cacheDir.absoluteFilePath(fileIdentity);
    // 确保文件目录存在
    if (!fileDir.exists()) {
        cacheDir.mkpath(fileIdentity);
    }
    QString fullPath = fileDir.absoluteFilePath(fileName);
    return fullPath;
}
bool UnifiedCacheManager::saveToCache(const QString& fileIdentity, int pageIndex, const QImage& image, double dpi)
{
    if (image.isNull() || fileIdentity.isEmpty()) {
        return false;
    }
    QMutexLocker locker(&m_mutex);
    // 使用getCacheKey生成简洁的目录名
    QString cacheKey = FileIdentityManager::getCacheKey(fileIdentity);
    QString cacheDir = m_cacheDirectory + "/" + cacheKey;
    QString fileName = QString("page_%1.png").arg(pageIndex, 5, 10, QChar('0'));
    QString filePath = cacheDir + "/" + fileName;
    // 确保目录存在
    QDir().mkpath(cacheDir);
    // 设置DPI信息到图片
    QImage imageWithDpi = image.copy();
    if (dpi > 0.0) {
        // 设置DPI，转换DPI到每米像素数（Qt的DPI单位是每米像素数）
        int dotsPerMeter = qRound(dpi * 1000 / 25.4);  // 1英寸 = 25.4毫米
        imageWithDpi.setDotsPerMeterX(dotsPerMeter);
        imageWithDpi.setDotsPerMeterY(dotsPerMeter);
    }
    // 保存图片
    bool success = imageWithDpi.save(filePath, "PNG", 90);  // 90%质量平衡大小和质量
    // 同时保存缩略图
    if (success) {
        QString thumbFileName = QString("thumb_%1.png").arg(pageIndex, 5, 10, QChar('0'));
        QString thumbDirPath = cacheDir + "/thumbnails";
        QString thumbFilePath = thumbDirPath + "/" + thumbFileName;
        // 确保缩略图目录存在
        QDir().mkpath(thumbDirPath);
        // 生成缩略图（最大200x200像素）
        QImage thumbnail = image.scaled(200, 200, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        bool thumbSuccess = thumbnail.save(thumbFilePath, "PNG", 50);  // 50%质量，文件更小
        if (thumbSuccess) {
        } else {
        }
    }
    if (success) {
        // 更新缓存项信息
        QString cacheKey = fileIdentity + "_" + QString::number(pageIndex);
        CacheItem item;
        item.filePath = filePath;
        item.createdTime = QDateTime::currentDateTime();
        item.lastAccessTime = QDateTime::currentDateTime();
        item.accessCount = 1;
        item.fileSize = QFileInfo(filePath).size();
        m_cacheItems[cacheKey] = item;
        // 检查是否需要清理缓存
        qint64 currentSize = getCacheSize();
        if (currentSize > m_maxCacheSize) {
            cleanupBySize(m_maxCacheSize * 0.8 / (1024 * 1024));  // 清理到80%
        }
        emit cacheSizeChanged(getCacheSize() / (1024 * 1024));
    }
    return success;
}
// === Martin Fowler重构：文件级缓存创建，自动记录缓存目录 ===
bool UnifiedCacheManager::saveToCacheWithFileInfo(UnifiedFileInfo& fileInfo, int pageIndex, const QImage& image, double dpi)
{
    if (image.isNull() || fileInfo.fileIdentity.isEmpty()) {
        return false;
    }
    QMutexLocker locker(&m_mutex);
    // === Martin Fowler修复：只有真正首次创建缓存的文件才记录缓存目录 ===
    // 检查文件是否已有任何缓存存在
    bool hasExistingCache = fileInfo.cacheDirectoryExists();
    if (fileInfo.isUsingGlobalCacheConfig() && !hasExistingCache) {
        // 只有使用全局配置且没有现有缓存的文件才记录新的缓存目录
        QString currentCacheDir = getCacheDirectory();
        fileInfo.setActualCacheDirectory(currentCacheDir);
    } else if (hasExistingCache) {
    }
    // 确保缓存目录存在
    if (!fileInfo.ensureCacheDirectoryExists()) {
        return false;
    }
    // 设置DPI信息到图片
    QImage imageWithDpi = image.copy();
    if (dpi > 0.0) {
        // 设置DPI，转换DPI到每米像素数（Qt的DPI单位是每米像素数）
        int dotsPerMeter = qRound(dpi * 1000 / 25.4);  // 1英寸 = 25.4毫米
        imageWithDpi.setDotsPerMeterX(dotsPerMeter);
        imageWithDpi.setDotsPerMeterY(dotsPerMeter);
    }
    // 使用文件级路径信息保存页面图片
    QString filePath = fileInfo.getPageCacheFilePath(pageIndex);
    bool success = imageWithDpi.save(filePath, "PNG", 90);  // 90%质量平衡大小和质量
    // 同时保存缩略图
    if (success) {
        QString thumbFilePath = fileInfo.getThumbnailCacheFilePath(pageIndex);
        QString thumbDir = fileInfo.getThumbnailCacheDirectory();
        // 确保缩略图目录存在
        QDir().mkpath(thumbDir);
        // 生成缩略图（最大200x200像素）
        QImage thumbnail = image.scaled(200, 200, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        bool thumbSuccess = thumbnail.save(thumbFilePath, "PNG", 50);  // 50%质量，文件更小
        if (thumbSuccess) {
        } else {
        }
    }
    if (success) {
        // 更新缓存项信息
        QString cacheKey = fileInfo.fileIdentity + "_" + QString::number(pageIndex);
        CacheItem item;
        item.filePath = filePath;
        item.createdTime = QDateTime::currentDateTime();
        item.lastAccessTime = QDateTime::currentDateTime();
        item.accessCount = 1;
        item.fileSize = QFileInfo(filePath).size();
        m_cacheItems[cacheKey] = item;
        // 检查是否需要清理缓存
        qint64 currentSize = getCacheSize();
        if (currentSize > m_maxCacheSize) {
            cleanupBySize(m_maxCacheSize * 0.8 / (1024 * 1024));  // 清理到80%
        }
        emit cacheSizeChanged(getCacheSize() / (1024 * 1024));
    }
    return success;
}
QImage UnifiedCacheManager::loadFromCache(const QString& fileIdentity, int pageIndex)
{
    QMutexLocker locker(&m_mutex);
    // 使用getCacheKey生成简洁的目录名
    QString cacheKey = FileIdentityManager::getCacheKey(fileIdentity);
    QString cacheDir = m_cacheDirectory + "/" + cacheKey;
    QString fileName = QString("page_%1.png").arg(pageIndex, 5, 10, QChar('0'));
    QString fullFilePath = cacheDir + "/" + fileName;
    // 检查文件是否存在
    if (!QFile::exists(fullFilePath)) {
        return QImage();
    }
    // 加载图片
    QImage image(fullFilePath);
    if (!image.isNull()) {
        // 更新内存映射（如果存在）
        QString memoryKey = fileIdentity + "_" + QString::number(pageIndex);
        if (m_cacheItems.contains(memoryKey)) {
            updateAccessInfo(memoryKey);
        } else {
            // 如果内存映射中不存在，添加它
            CacheItem item;
            item.filePath = fullFilePath;
            item.createdTime = QDateTime::currentDateTime();
            item.lastAccessTime = QDateTime::currentDateTime();
            item.accessCount = 1;
            item.fileSize = QFileInfo(fullFilePath).size();
            m_cacheItems[memoryKey] = item;
        }
    } else {
    }
    return image;
}
bool UnifiedCacheManager::isCached(const QString& fileIdentity, int pageIndex)
{
    QMutexLocker locker(&m_mutex);
    // 使用getCacheKey生成简洁的目录名
    QString cacheKey = FileIdentityManager::getCacheKey(fileIdentity);
    QString cacheDir = m_cacheDirectory + "/" + cacheKey;
    QString fileName = QString("page_%1.png").arg(pageIndex, 5, 10, QChar('0'));
    QString filePath = cacheDir + "/" + fileName;
    // 直接检查文件是否存在，不依赖内存映射
    return QFile::exists(filePath);
}
void UnifiedCacheManager::updateAccessInfo(const QString& cacheKey)
{
    if (m_cacheItems.contains(cacheKey)) {
        CacheItem& item = m_cacheItems[cacheKey];
        item.lastAccessTime = QDateTime::currentDateTime();
        item.accessCount++;
    }
}
void UnifiedCacheManager::clearCache(const QString& originalPath)
{
    QMutexLocker locker(&m_mutex);
    QList<QString> keysToRemove;
    for (auto it = m_cacheItems.begin(); it != m_cacheItems.end(); ++it) {
        // 现在所有缓存项都是基于fileIdentity的，直接清空所有缓存
        QFile::remove(it.value().filePath);
        keysToRemove.append(it.key());
    }
    for (const QString& key : keysToRemove) {
        m_cacheItems.remove(key);
    }
    emit cacheCleared();
    emit cacheSizeChanged(getCacheSize() / (1024 * 1024));
}
void UnifiedCacheManager::cleanupOldCache(int daysOld)
{
    // 临时缓存不需要清理旧数据，程序退出时会自动清除
}
void UnifiedCacheManager::cleanupBySize(qint64 maxSizeMB)
{
    // 临时缓存不需要按大小清理，程序退出时会自动清除
}
QList<QString> UnifiedCacheManager::getLRUItems(int count)
{
    // 按最后访问时间排序，返回最久未访问的项目
    QList<QPair<QString, QDateTime>> items;
    for (auto it = m_cacheItems.begin(); it != m_cacheItems.end(); ++it) {
        items.append(qMakePair(it.key(), it.value().lastAccessTime));
    }
    std::sort(items.begin(), items.end(), 
              [](const QPair<QString, QDateTime>& a, const QPair<QString, QDateTime>& b) {
                  return a.second < b.second;
              });
    QList<QString> result;
    for (int i = 0; i < qMin(count, items.size()); ++i) {
        result.append(items[i].first);
    }
    return result;
}
qint64 UnifiedCacheManager::getCacheSize() const
{
    qint64 totalSize = 0;
    for (const CacheItem& item : m_cacheItems) {
        totalSize += item.fileSize;
    }
    return totalSize;
}
qint64 UnifiedCacheManager::getActualCacheSize() const
{
    QDir cacheDir(m_cacheDirectory);
    if (!cacheDir.exists()) {
        return 0;
    }
    qint64 totalSize = 0;
    // 使用QDir::entryInfoList进行高效递归统计
    QDirIterator iterator(cacheDir.absolutePath(), 
                         QDir::Files | QDir::NoSymLinks, 
                         QDirIterator::Subdirectories);
    while (iterator.hasNext()) {
        iterator.next();
        QFileInfo fileInfo = iterator.fileInfo();
        if (fileInfo.isFile()) {
            totalSize += fileInfo.size();
        }
    }
    return totalSize;
}
qint64 UnifiedCacheManager::getCachedActualSize() const
{
    QDateTime now = QDateTime::currentDateTime();
    // 如果缓存过期或未初始化，重新扫描
    if (m_lastSizeUpdate.isNull() || 
        m_lastSizeUpdate.secsTo(now) > SIZE_CACHE_DURATION_SECONDS) {
        refreshActualCacheSize();
    }
    return m_cachedActualSize;
}
void UnifiedCacheManager::refreshActualCacheSize() const
{
    m_cachedActualSize = getActualCacheSize();
    m_lastSizeUpdate = QDateTime::currentDateTime();
}
int UnifiedCacheManager::getCacheCount() const
{
    return m_cacheItems.size();
}
QHash<QString, QList<UnifiedCacheManager::CacheItem>> UnifiedCacheManager::getCacheInfo() const
{
    QHash<QString, QList<CacheItem>> result;
    for (const CacheItem& item : m_cacheItems) {
        // 现在使用filePath作为键，因为originalPath已经移除
        QString key = QFileInfo(item.filePath).dir().dirName(); // 使用缓存目录名作为键
        result[key].append(item);
    }
    return result;
}
void UnifiedCacheManager::removeCacheItem(const QString& cacheKey)
{
    if (m_cacheItems.contains(cacheKey)) {
        CacheItem& item = m_cacheItems[cacheKey];
        QFile::remove(item.filePath);
        m_cacheItems.remove(cacheKey);
        emit cacheSizeChanged(getCacheSize() / (1024 * 1024));
    }
}
QList<QImage> UnifiedCacheManager::loadAllThumbnails(const QString& fileIdentity, int totalPages)
{
    QList<QImage> thumbnails;
    QMutexLocker locker(&m_mutex);
    // 使用getCacheKey生成简洁的目录名
    QString cacheKey = FileIdentityManager::getCacheKey(fileIdentity);
    QDir cacheDir(m_cacheDirectory);
    QDir fileDir = cacheDir.absoluteFilePath(cacheKey);
    if (!fileDir.exists()) {
        return thumbnails;
    }
    // 批量加载缩略图，使用定时器避免UI阻塞
    QDir thumbDir = fileDir.absoluteFilePath("thumbnails");
    for (int i = 0; i < totalPages; ++i) {
        QString thumbFileName = QString("thumb_%1.png").arg(i, 5, 10, QChar('0'));
        QString thumbFilePath = thumbDir.absoluteFilePath(thumbFileName);
        if (QFile::exists(thumbFilePath)) {
            QImage thumbnail(thumbFilePath);
            if (!thumbnail.isNull()) {
                thumbnails.append(thumbnail);
            } else {
                // 如果缩略图损坏，创建占位符
                QImage placeholder(200, 200, QImage::Format_RGB32);
                placeholder.fill(QColor(240, 240, 240));
                thumbnails.append(placeholder);
            }
        } else {
            // 如果缩略图不存在，创建占位符
            QImage placeholder(200, 200, QImage::Format_RGB32);
            placeholder.fill(QColor(240, 240, 240));
            thumbnails.append(placeholder);
        }
        // 每加载100个缩略图就处理一次事件，避免UI阻塞
        if (i % 100 == 0 && i > 0) {
            locker.unlock();
            QApplication::processEvents();
            locker.relock();
        }
    }
    return thumbnails;
}
QString UnifiedCacheManager::getFileIdentityForPath(const QString& originalPath) const
{
    // 直接返回getCacheKey，简化缓存目录结构
    QString fileIdentity = FileIdentityManager::getFileIdentity(originalPath);
    QString cacheKey = FileIdentityManager::getCacheKey(fileIdentity);
    return cacheKey;
}
QString UnifiedCacheManager::getCacheDirFor(const QString& originalPath) const
{
    QString cacheKey = getFileIdentityForPath(originalPath);
    return QDir(m_cacheDirectory).absoluteFilePath(cacheKey);
}
int UnifiedCacheManager::getCachedPageCount(const QString& originalPath) const
{
    QString dirPath = getCacheDirFor(originalPath);
    QDir d(dirPath);
    if (!d.exists()) {
        return 0;
    }
    QStringList files = d.entryList(QStringList() << "*.png", QDir::Files, QDir::Name);
    // 排除缩略图目录和manifest文件，只保留页面文件
    QStringList pageFiles;
    for (const QString& file : files) {
        if (file.startsWith("page_") && file.endsWith(".png")) {
            pageFiles.append(file);
        }
    }
    files = pageFiles;
    return files.size();
}
QDateTime UnifiedCacheManager::getCachedLatestTime(const QString& originalPath) const
{
    QString dirPath = getCacheDirFor(originalPath);
    QDir d(dirPath);
    if (!d.exists()) return QDateTime();
    QDateTime latest;
    QFileInfoList infos = d.entryInfoList(QStringList() << "*.png", QDir::Files, QDir::Time);
    for (const QFileInfo& fi : infos) {
        if (!latest.isValid() || fi.lastModified() > latest) latest = fi.lastModified();
    }
    return latest;
}
bool UnifiedCacheManager::cacheExistsWithPages(const QString& originalPath) const
{
    QString dirPath = getCacheDirFor(originalPath);
    QDir d(dirPath);
    if (!d.exists()) return false;
    return getCachedPageCount(originalPath) > 0;
}
bool UnifiedCacheManager::writeManifest(const QString& originalPath, int pageCount, const QDateTime& generatedAt,
                       const QString& engineVersion, const QString& extra, double dpi) const
{
    QString dirPath = getCacheDirFor(originalPath);
    QDir d(dirPath);
    if (!d.exists()) {
        QDir().mkpath(dirPath);
    }
    QString manifestPath = d.absoluteFilePath("manifest.json");
    QFile f(manifestPath);
    if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
        return false;
    }
    QTextStream s(&f);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
    s.setEncoding(QStringConverter::Utf8);
#endif
    QString json = QString(
        "{\n"
        "  \"file\": \"%1\",\n"
        "  \"hash\": \"%2\",\n"
        "  \"pageCount\": %3,\n"
        "  \"generatedAt\": \"%4\",\n"
        "  \"engineVersion\": \"%5\",\n"
        "  \"extra\": \"%6\","
        "  \"dpi\": %7\n"
        "}\n"
    ).arg(QString(originalPath).replace("\\", "\\\\").replace("\"", "\\\""))
     .arg(getFileIdentityForPath(originalPath))
     .arg(pageCount)
     .arg(generatedAt.toString("yyyy-MM-dd hh:mm:ss"))
     .arg(engineVersion)
     .arg(QString(extra).replace("\\", "\\\\").replace("\"", "\\\""))
     .arg(dpi);
    s << json;
    f.close();
    return true;
}
bool UnifiedCacheManager::isCacheDpiMatch(const QString& originalPath, double requiredDpi) const
{
    QString dirPath = getCacheDirFor(originalPath);
    QString manifestPath = dirPath + "/manifest.json";
    QFile file(manifestPath);
    if (!file.exists()) {
        return false; // 没有manifest，说明没有有效缓存
    }
    if (!file.open(QIODevice::ReadOnly)) {
        return false;
    }
    QByteArray data = file.readAll();
    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull()) {
        return false;
    }
    QJsonObject obj = doc.object();
    double cachedDpi = obj.value("dpi").toDouble(0.0);
    // 如果manifest中没有DPI字段或DPI不匹配，返回false
    if (cachedDpi <= 0.0 || qAbs(cachedDpi - requiredDpi) > 0.1) {
        return false;
    }
    return true;
}
bool UnifiedCacheManager::clearFileCache(const QString& filePath)
{
    // 获取文件的缓存目录
    QString cacheDir = getCacheDirFor(filePath);
    QDir dir(cacheDir);
    if (!dir.exists()) {
        return false;
    }
    // 删除整个缓存目录
    bool success = dir.removeRecursively();
    if (success) {
        // 清理内存中的缓存项
        QMutexLocker locker(&m_mutex);
        QList<QString> keysToRemove;
        for (auto it = m_cacheItems.begin(); it != m_cacheItems.end(); ++it) {
            if (it.value().filePath.startsWith(cacheDir)) {
                keysToRemove.append(it.key());
            }
        }
        for (const QString& key : keysToRemove) {
            m_cacheItems.remove(key);
        }
        emit cacheSizeChanged(getCacheSize() / (1024 * 1024));
    } else {
    }
    return success;
}
bool UnifiedCacheManager::clearAllCache()
{
    QString cacheDir = getCacheDirectory();
    QDir dir(cacheDir);
    if (!dir.exists()) {
        return true; // 目录不存在视为成功
    }
    // 等待所有文件操作完成
    QThread::msleep(1000); // 等待1秒确保所有文件操作完成
    // 删除缓存目录下的所有子目录和文件
    bool success = true;
    QStringList entries = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
    for (const QString& entry : entries) {
        QString entryPath = cacheDir + "/" + entry;
        QFileInfo fileInfo(entryPath);
        if (fileInfo.isDir()) {
            // 删除子目录 - 使用重试机制
            QDir subDir(entryPath);
            bool deleted = false;
            int retryCount = 0;
            const int maxRetries = 3;
            while (!deleted && retryCount < maxRetries) {
                if (subDir.removeRecursively()) {
                    deleted = true;
                } else {
                    retryCount++;
                    if (retryCount < maxRetries) {
                        QThread::msleep(500); // 等待500ms后重试
                    }
                }
            }
            if (!deleted) {
                success = false;
            }
        } else if (fileInfo.isFile()) {
            // 删除文件 - 使用重试机制
            bool deleted = false;
            int retryCount = 0;
            const int maxRetries = 3;
            while (!deleted && retryCount < maxRetries) {
                if (QFile::remove(entryPath)) {
                    deleted = true;
                } else {
                    retryCount++;
                    if (retryCount < maxRetries) {
                        QThread::msleep(500); // 等待500ms后重试
                    }
                }
            }
            if (!deleted) {
                success = false;
            }
        }
    }
    if (success) {
        // 清理内存中的缓存项
        QMutexLocker locker(&m_mutex);
        m_cacheItems.clear();
        emit cacheSizeChanged(0);
        emit allCacheDeleted();
    } else {
    }
    return success;
}
// ====== 导出缓存实现 ======
QString UnifiedCacheManager::getExportCacheDirectory() const
{
    if (m_exportCacheDirectory.isEmpty()) {
        m_exportCacheDirectory = QDir(getCacheDirectory()).absoluteFilePath("export_cache");
        QDir().mkpath(m_exportCacheDirectory);
    }
    return m_exportCacheDirectory;
}
QString UnifiedCacheManager::generateExportHash(const QString& settingsJson)
{
    // 使用MD5生成设置的哈希值
    QCryptographicHash hash(QCryptographicHash::Md5);
    hash.addData(settingsJson.toUtf8());
    return QString(hash.result().toHex());
}
QString UnifiedCacheManager::getExportCacheFilePath(const QString& filePath, const QString& exportHash) const
{
    QString fileHash = FileIdentityManager::getFileIdentity(filePath);
    QString fileName = QString("%1_%2.pdf").arg(fileHash).arg(exportHash);
    return QDir(getExportCacheDirectory()).absoluteFilePath(fileName);
}
bool UnifiedCacheManager::saveExportCache(const QString& filePath, const QString& exportHash, const QString& pdfPath)
{
    QMutexLocker locker(&m_mutex);
    QString cacheFilePath = getExportCacheFilePath(filePath, exportHash);
    // 复制PDF文件到缓存位置
    if (QFile::exists(cacheFilePath)) {
        QFile::remove(cacheFilePath);
    }
    if (!QFile::copy(pdfPath, cacheFilePath)) {
        return false;
    }
    // 更新缓存记录
    ExportCacheEntry entry;
    entry.filePath = filePath;
    entry.exportHash = exportHash;
    entry.tempPdfPath = cacheFilePath;
    entry.createdTime = QDateTime::currentDateTime();
    entry.fileSize = QFileInfo(cacheFilePath).size();
    entry.isValid = true;
    QString cacheKey = QString("%1_%2").arg(filePath).arg(exportHash);
    m_exportCache[cacheKey] = entry;
    saveExportCacheIndex();
    return true;
}
QString UnifiedCacheManager::getExportCache(const QString& filePath, const QString& exportHash)
{
    QMutexLocker locker(&m_mutex);
    QString cacheKey = QString("%1_%2").arg(filePath).arg(exportHash);
    if (!m_exportCache.contains(cacheKey)) {
        return QString();
    }
    const ExportCacheEntry& entry = m_exportCache[cacheKey];
    if (!isExportCacheValid(entry)) {
        // 移除无效缓存
        m_exportCache.remove(cacheKey);
        if (QFile::exists(entry.tempPdfPath)) {
            QFile::remove(entry.tempPdfPath);
        }
        saveExportCacheIndex();
        return QString();
    }
    return entry.tempPdfPath;
}
bool UnifiedCacheManager::hasValidExportCache(const QString& filePath, const QString& exportHash)
{
    return !getExportCache(filePath, exportHash).isEmpty();
}
bool UnifiedCacheManager::isExportCacheValid(const ExportCacheEntry& entry) const
{
    // 检查文件是否存在
    if (!QFile::exists(entry.tempPdfPath)) {
        return false;
    }
    // 检查源文件是否仍然存在且未被修改
    QFileInfo sourceInfo(entry.filePath);
    if (!sourceInfo.exists()) {
        return false;
    }
    // 检查缓存是否过期（默认7天）
    QDateTime now = QDateTime::currentDateTime();
    if (entry.createdTime.daysTo(now) > 7) {
        return false;
    }
    return true;
}
void UnifiedCacheManager::clearExportCache(const QString& filePath)
{
    QMutexLocker locker(&m_mutex);
    if (filePath.isEmpty()) {
        // 清除所有导出缓存
        for (const ExportCacheEntry& entry : m_exportCache) {
            if (QFile::exists(entry.tempPdfPath)) {
                QFile::remove(entry.tempPdfPath);
            }
        }
        m_exportCache.clear();
    } else {
        // 清除特定文件的导出缓存
        QStringList keysToRemove;
        for (auto it = m_exportCache.begin(); it != m_exportCache.end(); ++it) {
            if (it.value().filePath == filePath) {
                if (QFile::exists(it.value().tempPdfPath)) {
                    QFile::remove(it.value().tempPdfPath);
                }
                keysToRemove << it.key();
            }
        }
        for (const QString& key : keysToRemove) {
            m_exportCache.remove(key);
        }
    }
    saveExportCacheIndex();
}
QList<UnifiedCacheManager::ExportCacheEntry> UnifiedCacheManager::getExportCacheEntries() const
{
    QMutexLocker locker(&m_mutex);
    return m_exportCache.values();
}
qint64 UnifiedCacheManager::getExportCacheSize() const
{
    QMutexLocker locker(&m_mutex);
    qint64 totalSize = 0;
    for (const ExportCacheEntry& entry : m_exportCache) {
        totalSize += entry.fileSize;
    }
    return totalSize;
}
void UnifiedCacheManager::cleanupExportCache(int maxAgeDays)
{
    QMutexLocker locker(&m_mutex);
    QDateTime cutoffTime = QDateTime::currentDateTime().addDays(-maxAgeDays);
    QStringList keysToRemove;
    for (auto it = m_exportCache.begin(); it != m_exportCache.end(); ++it) {
        const ExportCacheEntry& entry = it.value();
        if (entry.createdTime < cutoffTime || !isExportCacheValid(entry)) {
            if (QFile::exists(entry.tempPdfPath)) {
                QFile::remove(entry.tempPdfPath);
            }
            keysToRemove << it.key();
        }
    }
    for (const QString& key : keysToRemove) {
        m_exportCache.remove(key);
    }
    if (!keysToRemove.isEmpty()) {
        saveExportCacheIndex();
    }
}
void UnifiedCacheManager::loadExportCache()
{
    QString indexPath = QDir(getExportCacheDirectory()).absoluteFilePath("index.json");
    if (!QFile::exists(indexPath)) {
        return;
    }
    QFile file(indexPath);
    if (!file.open(QIODevice::ReadOnly)) {
        return;
    }
    QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
    QJsonObject rootObj = doc.object();
    QJsonArray entriesArray = rootObj["entries"].toArray();
    for (const QJsonValue& value : entriesArray) {
        QJsonObject entryObj = value.toObject();
        ExportCacheEntry entry;
        entry.filePath = entryObj["filePath"].toString();
        entry.exportHash = entryObj["exportHash"].toString();
        entry.tempPdfPath = entryObj["tempPdfPath"].toString();
        entry.createdTime = QDateTime::fromString(entryObj["createdTime"].toString(), Qt::ISODate);
        entry.fileSize = entryObj["fileSize"].toDouble();
        entry.isValid = entryObj["isValid"].toBool();
        QString cacheKey = QString("%1_%2").arg(entry.filePath).arg(entry.exportHash);
        m_exportCache[cacheKey] = entry;
    }
}
void UnifiedCacheManager::saveExportCacheIndex()
{
    QString indexPath = QDir(getExportCacheDirectory()).absoluteFilePath("index.json");
    QJsonObject rootObj;
    QJsonArray entriesArray;
    for (const ExportCacheEntry& entry : m_exportCache) {
        QJsonObject entryObj;
        entryObj["filePath"] = entry.filePath;
        entryObj["exportHash"] = entry.exportHash;
        entryObj["tempPdfPath"] = entry.tempPdfPath;
        entryObj["createdTime"] = entry.createdTime.toString(Qt::ISODate);
        entryObj["fileSize"] = entry.fileSize;
        entryObj["isValid"] = entry.isValid;
        entriesArray.append(entryObj);
    }
    rootObj["entries"] = entriesArray;
    rootObj["version"] = "1.0";
    rootObj["lastUpdated"] = QDateTime::currentDateTime().toString(Qt::ISODate);
    QFile file(indexPath);
    if (!file.open(QIODevice::WriteOnly)) {
        return;
    }
    QJsonDocument doc(rootObj);
    file.write(doc.toJson());
}
// === 空间监控机制实现 ===
qint64 UnifiedCacheManager::getAvailableDiskSpace() const
{
    QString cacheDir = getCacheDirectory();
    QStorageInfo storage(cacheDir);
    if (storage.isValid()) {
        return storage.bytesAvailable();
    }
    return -1; // 无法获取信息
}
double UnifiedCacheManager::getAvailableDiskSpaceGB() const
{
    qint64 bytes = getAvailableDiskSpace();
    if (bytes < 0) {
        return -1.0;
    }
    return static_cast<double>(bytes) / (1024.0 * 1024.0 * 1024.0);
}
bool UnifiedCacheManager::hasEnoughDiskSpace(int thresholdGB) const
{
    double availableGB = getAvailableDiskSpaceGB();
    if (availableGB < 0) {
        return true; // 无法检测时假定有足够空间
    }
    return availableGB > thresholdGB;
}
QString UnifiedCacheManager::getSpaceStatusText(int thresholdGB) const
{
    double availableGB = getAvailableDiskSpaceGB();
    if (availableGB < 0) {
        return "无法检测磁盘空间";
    }
    if (availableGB > thresholdGB) {
        return QString("磁盘空间充足：%.1f GB可用").arg(availableGB);
    } else {
        return QString("磁盘空间不足：仅%.1f GB可用，低于%1 GB阈值").arg(availableGB).arg(thresholdGB);
    }
}
void UnifiedCacheManager::startSpaceMonitoring(int thresholdGB, int checkIntervalMs)
{
    m_spaceThresholdGB = thresholdGB;
    // 停止现有监控
    stopSpaceMonitoring();
    // 创建定时器
    m_spaceMonitorTimer = new QTimer(this);
    connect(m_spaceMonitorTimer, &QTimer::timeout, this, &UnifiedCacheManager::checkDiskSpace);
    // 启动监控
    m_spaceMonitorTimer->start(checkIntervalMs);
    m_spaceMonitoringActive = true;
    // 立即检查一次
    checkDiskSpace();
}
void UnifiedCacheManager::stopSpaceMonitoring()
{
    if (m_spaceMonitorTimer) {
        m_spaceMonitorTimer->stop();
        m_spaceMonitorTimer->deleteLater();
        m_spaceMonitorTimer = nullptr;
    }
    m_spaceMonitoringActive = false;
}
void UnifiedCacheManager::checkDiskSpace()
{
    if (!m_spaceMonitoringActive) {
        return;
    }
    double availableGB = getAvailableDiskSpaceGB();
    bool hasEnoughSpace = hasEnoughDiskSpace(m_spaceThresholdGB);
    // 状态变化时才发出信号，避免重复警告
    if (hasEnoughSpace != m_lastSpaceCheckResult) {
        m_lastSpaceCheckResult = hasEnoughSpace;
        if (hasEnoughSpace) {
            emit diskSpaceOk(availableGB, m_spaceThresholdGB);
        } else {
            emit diskSpaceLow(availableGB, m_spaceThresholdGB);
            emit diskSpaceWarning(QString("磁盘空间不足：仅%.1f GB可用，建议清理缓存或更改缓存目录").arg(availableGB));
        }
    }
}
// === Martin Fowler重构：文件级缓存路径管理实现 ===
QString UnifiedCacheManager::getCacheDirForFileInfo(const UnifiedFileInfo& fileInfo) const
{
    return fileInfo.getFullCacheDirectory();
}
bool UnifiedCacheManager::clearFileCacheWithFileInfo(const UnifiedFileInfo& fileInfo)
{
    QString cacheDir = fileInfo.getFullCacheDirectory();
    QDir dir(cacheDir);
    if (!dir.exists()) {
        return false; // 缓存不存在也不算错误
    }
    // 删除整个缓存目录
    bool success = dir.removeRecursively();
    if (success) {
        // 清理内存中的缓存项
        QString cacheKey = FileIdentityManager::getCacheKey(fileInfo.fileIdentity);
        removeCacheItem(cacheKey);
        emit cacheSizeChanged(getActualCacheSize());
    } else {
    }
    return success;
}
